#include<stdio.h>
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>

using namespace std;

#define MAX_QUEUE 5

template<class T>
class BlockQueue{
  public:
    BlockQueue(int capacity = MAX_QUEUE):_capacity(capacity)
    {
      pthread_mutex_init(&_mutex,NULL);
      pthread_cond_init(&_cond_con,NULL);
      pthread_cond_init(&_cond_pro,NULL);
    }
    ~BlockQueue()
    {
      pthread_mutex_destroy(&_mutex);
      pthread_cond_destroy(&_cond_con);
      pthread_cond_destroy(&_cond_pro);
    }
    void Push(const T& data)
    {
      //生产者进行数据的读取操作
      pthread_mutex_lock(&_mutex);
      while(_q.size()==_capacity){
        //容量已满不能在读取数据
        //进行阻塞
        pthread_cond_wait(&_cond_pro,&_mutex);
      }
      _q.push(data);
      //唤醒消费者来进行数据的处理
      pthread_cond_signal(&_cond_con);
      pthread_mutex_unlock(&_mutex);
    }
    void Pop(T* data)
    {
      pthread_mutex_lock(&_mutex);
      while(_q.empty()){
        //当前队列为空，消费者不能从中读取数据，进行阻塞
        pthread_cond_wait(&_cond_con,&_mutex);
      }
      *data=_q.front();  //获取数据
      _q.pop();
      //唤醒生产者读取新的数据到消息缓存队列中
     pthread_cond_signal(&_cond_pro);
     pthread_mutex_unlock(&_mutex);

    }
  private:
    queue<T> _q;
    int _capacity;
    pthread_mutex_t _mutex; 
    pthread_cond_t _cond_con; //消费者条件变量
    pthread_cond_t _cond_pro;   //生产者条件变量
};

#define MAX_USER 5

void* consumer(void* arg)
{
  BlockQueue<int> *q=(BlockQueue<int> *)arg;
  while(1){
    //消费者读取数据
    int data;
    q->Pop(&data);
    printf("%p 线程获取到了数据-------- %d\n",pthread_self(),data);
  }
  return NULL;
}

void* productor(void* arg)
{
  BlockQueue<int> *q=(BlockQueue<int> *)arg;
  int data=0;
  while(1){
    //生产者进行数据的获取
    q->Push(data);
    printf("%p 线程入队了数据 : %d\n",pthread_self(),data++);
  }
  return NULL;
}

int main()
{
  BlockQueue<int> q;
  pthread_t con_tid[MAX_USER],pro_tid[MAX_USER];
  int ret;
 
  //线程创建
  for(int i=0;i<MAX_USER;++i){
    ret=pthread_create(&con_tid[i],NULL,consumer,(void*)&q);
    if(ret!=0){
      perror("pthread_creat error!\n");
      return -1;
    }
    ret=pthread_create(&pro_tid[i],NULL,productor,(void*)&q);
    if(ret!=0){
      perror("pthread_creat error!\n");
      return -1;
    }
  }

  //线程等待
  for(int i=0;i<MAX_USER;++i){
    pthread_join(con_tid[i],NULL);
    pthread_join(pro_tid[i],NULL);
  }

  return 0;
}




